#include "utils.hpp"
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <algorithm>

namespace icecode {
  namespace utils {

    std::vector<std::string> splitString(std::string str, std::string tokens, bool removeEmpty)
    {
      std::string tgt;
      std::vector<std::string> res;

      tgt.reserve(str.size());
      std::for_each(str.cbegin(), str.cend(), [&](const char c) {
	  if(tokens.find(c) != std::string::npos) //found
	    {
	      if(!tgt.empty() || !removeEmpty)
		{
		  res.push_back(tgt);
		  tgt.clear();
		}
	    }
	  else
	    {
	      tgt.resize(tgt.size() + 1);
	      *(tgt.end() - 1) = c;
	    }
	});

      if(!tgt.empty() || !removeEmpty)
	res.push_back(tgt);
      return res;
    }

    std::string joinString(std::vector<std::string> s, std::string token)
    {
      if(s.size() > 0)
	{
	  std::string res = s[0];
	  
	  if(s.size() > 1)
	    std::for_each(s.begin() + 1, s.end(), [&](std::string& str) { res += token + str; });

	  return res;
	}

      return "";
    }

    std::string normalizePath(std::string path, icecode::PasswdFile& auth)
    {
      static std::string home = ::getenv("HOME");
      static std::string pwd = ::getenv("PWD");
      std::string norm;

      switch(path[0])
	{
	case '~': //relative path (to user's home directory)
	  if(path.size() == 1)
	    norm = home;
	  else
	    {
	      if(path[1] == '/') //current user
		norm = home;
	      else
		{
		  //Add other user's dir
		}
	      path.erase(path.begin(), static_cast<std::string::iterator>(path.find_first_of('/') + path.begin()));
	      norm.append(path);
	    }
	  break;
	case '/': //nothing to do, absolute path
	  norm = path;
	  break;
	default: //relative path (to current directory)
	  norm = pwd + "/" + path;
	  break;
	}

      {
	std::vector<std::string> dirs = splitString(norm, "/");
	bool split;

	do{
	  split = false;

	  for(auto it = dirs.begin(); it != dirs.end(); it++)
	    if(*it == ".") {
	      dirs.erase(it);
	      split = true;
	      break;
	    }
	    else if(*it == ".." && it != dirs.begin()) {
	      dirs.erase(it - 1, it + 1);
	      split = true;
	      break;
	    }
	} while(split);

	norm = "/" + joinString(dirs, "/");
      }

      return norm;
    }

    std::string trimLeft(std::string src, std::string trim_chars)
    {
      if(!src.empty())
	for(auto it = src.begin(); it <= src.end(); it++) {
	  if(trim_chars.find(*it) == std::string::npos) { //not a valid char
	    src.erase(src.begin(), it);
	    break;
	  }
	  else if (it == src.end()) {
	    src.clear();
	    break;
	  }
	}

      return src;
    }

    std::string trimRight(std::string src, std::string trim_chars)
    {
      if(!src.empty())
	for(auto it = src.end() - 1; it >= src.begin(); it--) {
	  if(trim_chars.find(*it) == std::string::npos) { //not a valid char
	    src.erase(it + 1, src.end());
	    break;
	  }
	  else if(it == src.begin()) {
	    src.clear();
	    break;
	  }
	}

      return src;
    }

    std::string trim(std::string src, std::string trim_chars)
    {
      return trimLeft(trimRight(src, trim_chars), trim_chars);
    }
  }
}
